#!/usr/bin/env node
// 控制台文本颜色
const path = require("node:path");
const { argv } = require("yargs");
require("dotenv").config({
    path: argv.dotenv || path.resolve(process.cwd(), ".env"),
    override: true,
});

// 禁用其他打印
console.yzplog = console.log;
console.log = () => {};
console.warn = () => {};
console.info = () => {};
console.error = () => {};

const mgr = require("./commands/mgr");
const {
    getLastError,
    info,
    setLogLevel,
    LogLevel,
    success,
    error,
    getLastErrorCode,
    error2,
    getLastCommand,
    getLastExecFile,
} = require("./utils/log_tool");
const { showAlert, showNotify } = require("./utils/alert_tool");
const { parse } = require("./utils/parse_tool");
const { shareData, clear_line_end } = require("./commands/share_data");
const { decode } = require("./utils/base64_tool");
const {
    formatTimeInMillisec,
    formatTimestampMillisec,
} = require("./utils/transform_tool");
const { hash } = require("./utils/hash_tool");
const { getCache, setCache } = require("./utils/cache_tool");
const { progress } = require("./utils/display_tool");

process.on("exit", (code) => {
    if (!code) {
        success(`>>> 任务结束 <<<`);
    } else {
        error(`>>> 任务异常结束 #${code} <<<`);
    }
});

setLogLevel(argv.LOG_LEVEL || LogLevel.INFO);
mgr.init();

/** @return {Promise<string>} */
async function getCfgs() {
    const cfgs = argv._[0];
    if (cfgs) return cfgs;
    return new Promise((resolve) => {
        process.stdin.on("data", (data) => {
            // 标准输入模式,启用全自动
            shareData.FULL_AUTOMATIC = 1;
            resolve(data.toString().trim());
        });
    });
}
async function MainProcess() {
    let lastError = null;
    const cfgs = await getCfgs();
    // 缓存Key考虑cfgs,  argv
    const hashSource = [cfgs, JSON.stringify(argv)].join("&&&");
    const cfgHash = hash(hashSource).toString();
    const enableTimer = argv.ENABLE_TIMER;
    const timerInterval = argv.TIMER_INTERVAL || 1000;
    const CACHE_KEY_ESTIMATE_TIME = `ESTIMATE_TIME_${cfgHash}`;
    const estimateTime =
        +argv.ESTIMATE_TIME || +(await getCache(CACHE_KEY_ESTIMATE_TIME)) || 0;
    const beginTime = Date.now();
    let timer;
    if (enableTimer && timerInterval) {
        timer = setInterval(() => {
            const elapsedTime = Date.now() - beginTime;
            if (!estimateTime) {
                info(
                    `\r[${formatTimestampMillisec(
                        Date.now(),
                    )}] 任务已运行 ${formatTimeInMillisec(
                        elapsedTime,
                        "hh:mm:ss",
                    )} ${clear_line_end}`,
                    "",
                );
            } else {
                const _estimateLeft = Math.max(0, estimateTime - elapsedTime);
                // info(`\r[${formatTimestampMillisec(Date.now())}] 任务已运行 ${formatTimeInMillisec(elapsedTime, "hh:mm:ss")}, 预计剩余 ${formatTimeInMillisec(estimateLeft, "hh:mm:ss")} ${clear_line_end}`, "");
                progress(elapsedTime, estimateTime, {
                    desc: "预计耗时",
                    format_time: true,
                });
            }
        }, timerInterval);
    }
    try {
        if (cfgs.indexOf(".") !== -1) {
            await mgr.exec(
                [
                    {
                        type: "exec_from_file",
                        data: {
                            src: cfgs,
                        },
                    },
                ],
                0,
                false,
            );
        } else {
            await mgr.exec(await parse(decode(cfgs), "yaml"), 0);
        }
        lastError = getLastError();
        lastError = lastError?.message || lastError;
    } catch (err) {
        lastError = err.message || err;
    }
    const endTime = shareData.AUTOMATOR_END_TIME || Date.now();
    const costTime = endTime - beginTime;
    if (enableTimer) {
        clearInterval(timer);
        info("");
        let timeLog = `任务总耗时 ${formatTimeInMillisec(costTime, "hh:mm:ss")}`;
        if (estimateTime) {
            const offsetTime = costTime - estimateTime;
            if (offsetTime > 0) {
                timeLog += `, 比预期慢了 ${formatTimeInMillisec(
                    offsetTime,
                    "hh:mm:ss SSS",
                )}`;
            } else {
                timeLog += `, 比预期快了 ${formatTimeInMillisec(
                    -offsetTime,
                    "hh:mm:ss SSS",
                )}`;
            }
        }
        success(`>>> ${timeLog} <<<`, undefined, undefined, true);
    }
    const code = lastError ? getLastErrorCode() || 1 : 0;
    const _extname = path.extname(argv.$0);
    const hasError = code !== 0;
    if (!hasError) {
        await setCache(CACHE_KEY_ESTIMATE_TIME, costTime);
    }
    info("");
    if (hasError) {
        var [lastCommand, lastCommandFormated] = getLastCommand();
        error2(
            "File:\n" +
                getLastExecFile() +
                "\nRaw:\n" +
                lastCommand +
                "\nFormated:\n" +
                JSON.stringify(lastCommandFormated, null, 4) +
                "\n" +
                lastError,
        );
    }
    if (shareData.ALERT_RESULT) {
        const title = `${shareData.TITLE || "任务即将结束"}`;
        await showAlert(
            hasError ? "error" : "info",
            hasError ? `✖ 失败, ${lastError}` : "✔ 成功!",
            title,
        );
    } else if (shareData.NOTIFY_RESULT) {
        const successIcon =
            shareData.SUCCESS_ICON ||
            `${shareData.AUTOMATOR_ROOT}/assets/success.png`;
        const errorIcon =
            shareData.ERROR_ICON ||
            `${shareData.AUTOMATOR_ROOT}/assets/error.png`;
        await showNotify({
            title: `${shareData.TITLE || cfgs}`,
            message: hasError ? lastError : `任务即将结束`,
            icon: hasError ? errorIcon : successIcon,
        });
    }
    // 手动调用 exit, 会导致异步的定时器事件失效
    if (shareData.EXIT_IMMEDIATELY) {
        process.exit(code);
    } else {
        process.exitCode = code;
    }
}

MainProcess();
